home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- * bbox.c
- *
- * This module implements the bounding box calculations.
- * This file was written by Alexander Enzmann. He wrote the code for
- * POV-Ray's bounding boxes and generously provided us these enhancements.
- * The box intersection code was further hacked by Eric Haines to speed it up.
- *
- * Just so everyone knows where this came from, the code is VERY heavily
- * based on the slab code from Mark VandeWettering's MTV raytracer.
- * POV-Ray is just joining the crowd of admirers of Mark's contribution to
- * the public domain. [ARE]
- *
- * from Persistence of Vision(tm) Ray Tracer
- * Copyright 1996 Persistence of Vision Team
- *---------------------------------------------------------------------------
- * NOTICE: This source code file is provided so that users may experiment
- * with enhancements to POV-Ray and to port the software to platforms other
- * than those supported by the POV-Ray Team. There are strict rules under
- * which you are permitted to use this file. The rules are in the file
- * named POVLEGAL.DOC which should be distributed with this file. If
- * POVLEGAL.DOC is not available or for more info please contact the POV-Ray
- * Team Coordinator by leaving a message in CompuServe's Graphics Developer's
- * Forum. The latest version of POV-Ray may be found there as well.
- *
- * This program is based on the popular DKB raytracer version 2.12.
- * DKBTrace was originally written by David K. Buck.
- * DKBTrace Ver 2.0-2.12 were written by David K. Buck & Aaron A. Collins.
- *
- *****************************************************************************/
-
- #include "frame.h"
- #include "vector.h"
- #include "povproto.h"
- #include "bbox.h"
- #include "matrices.h"
- #include "objects.h"
- #include "povray.h"
- #include "render.h"
-
-
-
- /*****************************************************************************
- * Local preprocessor defines
- ******************************************************************************/
-
- #define BUNCHING_FACTOR 4
-
- /* Initial number of entries in a priority queue. */
-
- #define INITIAL_PRIORITY_QUEUE_SIZE 256
-
-
-
- /*****************************************************************************
- * Local typedefs
- ******************************************************************************/
-
-
-
- /*****************************************************************************
- * Static functions
- ******************************************************************************/
-
- static BBOX_TREE *create_bbox_node PARAMS((int size));
-
- static int find_axis PARAMS((BBOX_TREE **Finite, long first, long last));
- static void calc_bbox PARAMS((BBOX *BBox, BBOX_TREE **Finite, long first, long last));
- static void build_area_table PARAMS((BBOX_TREE **Finite, long a, long b, DBL *areas));
- static int sort_and_split PARAMS((BBOX_TREE **Root, BBOX_TREE **Finite, long *nFinite, long first, long last));
-
- static void priority_queue_insert PARAMS((PRIORITY_QUEUE *Queue, DBL Depth, BBOX_TREE *Node));
-
- static int CDECL compboxes PARAMS((CONST void *in_a, CONST void *in_b));
-
-
- /*****************************************************************************
- * Local variables
- ******************************************************************************/
-
- /* Current axis to sort along. */
-
- static int Axis = 0;
-
- /* Number of finite elements. */
-
- static long maxfinitecount = 0;
-
- /* Priority queue used for frame level bouning box hierarchy. */
-
- static PRIORITY_QUEUE *Frame_Queue;
-
- /* Top node of bounding hierarchy. */
-
- BBOX_TREE *Root_Object;
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Initialize_BBox_Code
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Initialize bbox specific variables.
- *
- * CHANGES
- *
- * Jul 1995 : Creation.
- *
- ******************************************************************************/
-
- void Initialize_BBox_Code()
- {
- Frame_Queue = Create_Priority_Queue(INITIAL_PRIORITY_QUEUE_SIZE);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Deinitialize_BBox_Code
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Deinitialize bbox specific variables.
- *
- * CHANGES
- *
- * Jul 1995 : Creation.
- *
- ******************************************************************************/
-
- void Deinitialize_BBox_Code()
- {
- if (Frame_Queue != NULL)
- {
- Destroy_Priority_Queue(Frame_Queue);
- }
-
- Frame_Queue = NULL;
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Priority_Queue
- *
- * INPUT
- *
- * QSize - initial size of priority queue
- *
- * OUTPUT
- *
- * RETURNS
- *
- * PRIORITY_QUEUE * - priority queue
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Create a priority queue.
- *
- * CHANGES
- *
- * Feb 1995 : Creation.
- *
- ******************************************************************************/
-
- PRIORITY_QUEUE *Create_Priority_Queue(QSize)
- unsigned QSize;
- {
- PRIORITY_QUEUE *New;
-
- New = (PRIORITY_QUEUE *)POV_MALLOC(sizeof(PRIORITY_QUEUE), "priority queue");
-
- New->Queue = (QELEM *)POV_MALLOC(QSize*sizeof(QELEM), "priority queue");
-
- New->QSize = 0;
-
- New->Max_QSize = QSize;
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Priority_Queue
- *
- * INPUT
- *
- * Queue - Priority queue
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Destroy a priority queue.
- *
- * CHANGES
- *
- * Feb 1995 : Creation.
- *
- ******************************************************************************/
-
- void Destroy_Priority_Queue(Queue)
- PRIORITY_QUEUE *Queue;
- {
- if (Queue != NULL)
- {
- POV_FREE(Queue->Queue);
-
- POV_FREE(Queue);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_BBox_Tree
- *
- * INPUT
- *
- * Node - Node to destroy
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Recursively destroy a bounding box tree.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Destroy_BBox_Tree(Node)
- BBOX_TREE *Node;
- {
- short i;
-
- if (Node != NULL)
- {
- if (Node->Entries > 0)
- {
- for (i = 0; i < Node->Entries; i++)
- {
- Destroy_BBox_Tree(Node->Node[i]);
- }
-
- POV_FREE(Node->Node);
-
- Node->Entries = 0;
-
- Node->Node = NULL;
- }
-
- POV_FREE(Node);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Recompute_BBox
- *
- * INPUT
- *
- * trans - Transformation
- *
- * OUTPUT
- *
- * bbox - Bounding box
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Recalculate a bounding box after a transformation.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Recompute_BBox(bbox, trans)
- BBOX *bbox;
- TRANSFORM *trans;
- {
- int i;
- VECTOR lower_left, lengths, corner;
- VECTOR mins, maxs;
-
- if (trans == NULL)
- {
- return;
- }
-
- Assign_BBox_Vect(lower_left, bbox->Lower_Left);
- Assign_BBox_Vect(lengths, bbox->Lengths);
-
- Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
-
- for (i = 1; i <= 8; i++)
- {
- Assign_Vector(corner, lower_left);
-
- corner[X] += ((i & 1) ? lengths[X] : 0.0);
- corner[Y] += ((i & 2) ? lengths[Y] : 0.0);
- corner[Z] += ((i & 4) ? lengths[Z] : 0.0);
-
- MTransPoint(corner, corner, trans);
-
- if (corner[X] < mins[X]) { mins[X] = corner[X]; }
- if (corner[X] > maxs[X]) { maxs[X] = corner[X]; }
- if (corner[Y] < mins[Y]) { mins[Y] = corner[Y]; }
- if (corner[Y] > maxs[Y]) { maxs[Y] = corner[Y]; }
- if (corner[Z] < mins[Z]) { mins[Z] = corner[Z]; }
- if (corner[Z] > maxs[Z]) { maxs[Z] = corner[Z]; }
- }
-
- /* Clip bounding box at the largest allowed bounding box. */
-
- if (mins[X] < -BOUND_HUGE / 2) { mins[X] = -BOUND_HUGE / 2; }
- if (mins[Y] < -BOUND_HUGE / 2) { mins[Y] = -BOUND_HUGE / 2; }
- if (mins[Z] < -BOUND_HUGE / 2) { mins[Z] = -BOUND_HUGE / 2; }
- if (maxs[X] > BOUND_HUGE / 2) { maxs[X] = BOUND_HUGE / 2; }
- if (maxs[Y] > BOUND_HUGE / 2) { maxs[Y] = BOUND_HUGE / 2; }
- if (maxs[Z] > BOUND_HUGE / 2) { maxs[Z] = BOUND_HUGE / 2; }
-
- Make_BBox_from_min_max(*bbox, mins, maxs);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Recompute_Inverse_BBox
- *
- * INPUT
- *
- * trans - Transformation
- *
- * OUTPUT
- *
- * bbox - Bounding box
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Recalculate a bounding box after a transformation.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Recompute_Inverse_BBox(bbox, trans)
- BBOX *bbox;
- TRANSFORM *trans;
- {
- int i;
- VECTOR lower_left, lengths, corner;
- VECTOR mins, maxs;
-
- if (trans == NULL)
- {
- return;
- }
-
- Assign_BBox_Vect(lower_left, bbox->Lower_Left);
- Assign_BBox_Vect(lengths, bbox->Lengths);
-
- Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
-
- for (i = 1; i <= 8; i++)
- {
- Assign_Vector(corner, lower_left);
-
- corner[X] += ((i & 1) ? lengths[X] : 0.0);
- corner[Y] += ((i & 2) ? lengths[Y] : 0.0);
- corner[Z] += ((i & 4) ? lengths[Z] : 0.0);
-
- MInvTransPoint(corner, corner, trans);
-
- if (corner[X] < mins[X]) { mins[X] = corner[X]; }
- if (corner[X] > maxs[X]) { maxs[X] = corner[X]; }
- if (corner[Y] < mins[Y]) { mins[Y] = corner[Y]; }
- if (corner[Y] > maxs[Y]) { maxs[Y] = corner[Y]; }
- if (corner[Z] < mins[Z]) { mins[Z] = corner[Z]; }
- if (corner[Z] > maxs[Z]) { maxs[Z] = corner[Z]; }
- }
-
- /* Clip bounding box at the largest allowed bounding box. */
-
- if (mins[X] < -BOUND_HUGE / 2) { mins[X] = -BOUND_HUGE / 2; }
- if (mins[Y] < -BOUND_HUGE / 2) { mins[Y] = -BOUND_HUGE / 2; }
- if (mins[Z] < -BOUND_HUGE / 2) { mins[Z] = -BOUND_HUGE / 2; }
- if (maxs[X] > BOUND_HUGE / 2) { maxs[X] = BOUND_HUGE / 2; }
- if (maxs[Y] > BOUND_HUGE / 2) { maxs[Y] = BOUND_HUGE / 2; }
- if (maxs[Z] > BOUND_HUGE / 2) { maxs[Z] = BOUND_H jects there are. */
-
- Render_Info("\nScene contains %ld frame level objects; %ld infinite.\n",
- nFinite + nInfinite, nInfinite);
-
- /* If bounding boxes aren't used we can return. */
-
- if (!opts.Use_Slabs || !(nFinite + nInfinite >= opts.BBox_Threshold))
- {
- opts.Use_Slabs = FALSE;
-
- return;
- }
-
- opts.Use_Slabs = TRUE;
-
- /*
- * This is a resonable guess at the number of finites needed.
- * This array will be reallocated as needed if it isn't.
- */
-
- maxfinitecount = 2 * nFinite;
-
- /*
- * Now allocate an array to hold references to these finites and
- * any new composite objects we may generate.
- */
-
- Finite = Infinite = NULL;
-
- if (nFinite > 0)
- {
- Finite = (BBOX_TREE **)POV_MALLOC(maxfinitecount*sizeof(BBOX_TREE *), "bounding boxes");
- }
-
- /* Create array to hold pointers to infinite objects. */
-
- if (nInfinite > 0)
- {
- Infinite = (BBOX_TREE **)POV_MALLOC(nInfinite*sizeof(BBOX_TREE *), "bounding boxes");
- }
-
- /* Init lists. */
-
- for (i = 0; i < nFinite; i++)
- {
- Finite[i] = create_bbox_node(0);
- }
-
- for (i = 0; i < nInfinite; i++)
- {
- Infinite[i] = create_bbox_node(0);
- }
-
- /* Set up finite and infinite object lists. */
-
- iFinite = iInfinite = 0;
-
- for (Object = Frame.Objects; Object != NULL; Object = Object->Sibling)
- {
- if (Object->Type & LIGHT_SOURCE_OBJECT)
- {
- Temp = ((LIGHT_SOURCE *)Object)->Children;
- }
- else
- {
- Temp = Object;
- }
-
- if (Temp != NULL)
- {
- /* Add object to the appropriate list. */
-
- if (Test_Flag(Temp, INFINITE_FLAG))
- {
- Infinite[iInfinite]->Infinite = TRUE;
- Infinite[iInfinite]->BBox = Temp->BBox;
- Infinite[iInfinite]->Node = (BBOX_TREE **)Temp;
-
- iInfinite++;
- }
- else
- {
- Finite[iFinite]->BBox = Temp->BBox;
- Finite[iFinite]->Node = (BBOX_TREE **)Temp;
-
- iFinite++;
- }
- }
- }
-
- /*
- * Now build the bounding box tree.
- */
-
- Build_BBox_Tree(Root, nFinite, Finite, nInfinite, Infinite);
-
- /* Get rid of the Finite and Infinite arrays and just use Root. */
-
- if (Finite != NULL)
- {
- POV_FREE(Finite);
- }
-
- if (Infinite != NULL)
- {
- POV_FREE(Infinite);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Destroy_Bounding_Slabs
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Destroy the bounding box hierarchy and the priority queue.
- *
- * CHANGES
- *
- * Sep 1994 : Added freeing of priority queue. [DB]
- *
- ******************************************************************************/
-
- void Destroy_Bounding_Slabs()
- {
- if (Root_Object != NULL)
- {
- Destroy_BBox_Tree(Root_Object);
-
- Root_Object = NULL;
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Intersect_BBox_Tree
- *
- * INPUT
- *
- * Root - Root node of the bbox tree
- * Ray - Current ray
- *
- * OUTPUT
- *
- * Best_Intersection - Nearest intersection found
- * Best_Object - Nearest object found
- *
- * RETURNS
- *
- * int - TRUE if an intersection was found
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Intersect a ray with a bounding box tree.
- *
- * CHANGES
- *
- * Sep 1994 : Moved priority queue allocation/freeing out of here. [DB]
- *
- ******************************************************************************/
-
- int Intersect_BBox_Tree(Root, Ray, Best_Intersection, Best_Object)
- BBOX_TREE *Root;
- RAY *Ray;
- INTERSECTION *Best_Intersection;
- OBJECT **Best_Object;
- {
- int i, found;
- DBL Depth;
- BBOX_TREE *Node;
- RAYINFO rayinfo;
- INTERSECTION New_Intersection;
-
- /* Create the direction vectors for this ray. */
-
- Create_Rayinfo(Ray, &rayinfo);
-
- /* Start with an empty priority queue. */
-
- found = FALSE;
-
- Frame_Queue->QSize = 0;
-
- #ifdef BBOX_EXTRA_STATS
- Increase_Counter(stats[totalQueueResets]);
- #endif
-
- /* Check top node. */
-
- Check_And_Enqueue(Frame_Queue, Root, &Root->BBox, &rayinfo);
-
- /* Check elements in the priority queue. */
-
- while (Frame_Queue->QSize)
- {
- Priority_Queue_Delete(Frame_Queue, &Depth, &Node);
-
- /*
- * If current intersection is larger than the best intersection found
- * so far our task is finished, because all other bounding boxes in
- * the priority queue are further away.
- */
-
- if (Depth > Best_Intersection->Depth)
- {
- break;
- }
-
- /* Check current node. */
-
- if (Node->Entries)
- {
- /* This is a node containing leaves to be checked. */
-
- for (i = 0; i < Node->Entries; i++)
- {
- Check_And_Enqueue(Frame_Queue, Node->Node[i], &Node->Node[i]->BBox, &rayinfo);
- }
- }
- else
- {
- /* This is a leaf so test contained object. */
-
- if (Intersection(&New_Intersection, (OBJECT *)Node->Node, Ray))
- {
- if (New_Intersection.Depth < Best_Intersection->Depth)
- {
- *Best_Intersection = New_Intersection;
-
- *Best_Object = (OBJECT *)Node->Node;
-
- found = TRUE;
- }
- }
- }
- }
-
- return (found);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * priority_queue_insert
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Insert an element in the priority queue.
- *
- * CHANGES
- *
- * Sep 1994 : Added code for resizing the priority queue. [DB]
- *
- ******************************************************************************/
-
- static void priority_queue_insert(Queue, Depth, Node)
- PRIORITY_QUEUE *Queue;
- DBL Depth;
- BBOX_TREE *Node;
- {
- unsigned size;
- int i;
- QELEM tmp, *List;
-
- #ifdef BBOX_EXTRA_STATS
- Increase_Counter(stats[totalQueues]);
- #endif
-
- Queue->QSize++;
-
- size = Queue->QSize;
-
- /* Reallocate priority queue if it's too small. */
-
- if (size >= Queue->Max_QSize)
- {
- if (size >= INT_MAX/2)
- {
- Error("Priority queue overflow.\n");
- }
-
- #ifdef BBOX_EXTRA_STATS
- Increase_Counter(stats[totalQueueResizes]);
- #endif
-
- Queue->Max_QSize *= 2;
-
- Queue->Queue = (QELEM *)POV_REALLOC(Queue->Queue, Queue->Max_QSize*sizeof(QELEM), "priority queue");
- }
-
- List = Queue->Queue;
-
- List[size].Depth = Depth;
- List[size].Node = Node;
-
- i = size;
-
- while (i > 1 && List[i].Depth < List[i / 2].Depth)
- {
- tmp = List[i];
-
- List[i] = List[i / 2];
-
- List[i / 2] = tmp;
-
- i = i / 2;
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Priority_Queue_Delete
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Get an element from the priority queue.
- *
- * NOTE: This element will always be the one closest to the ray origin.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- void Priority_Queue_Delete(Queue, Depth, Node)
- PRIORITY_QUEUE *Queue;
- DBL *Depth;
- BBOX_TREE **Node;
- {
- QELEM tmp, *List;
- int i, j;
- unsigned size;
-
- if (Queue->QSize == 0)
- {
- Error("priority queue is empty.\n");
- }
-
- List = Queue->Queue;
-
- *Depth = List[1].Depth;
- *Node = List[1].Node;
-
- List[1] = List[Queue->QSize];
-
- Queue->QSize--;
-
- size = Queue->QSize;
-
- i = 1;
-
- while (2 * i <= (int)size)
- {
- if (2 * i == (int)size)
- {
- j = 2 * i;
- }
- else
- {
- if (List[2*i].Depth < List[2*i+1].Depth)
- {
- j = 2 * i;
- }
- else
- {
- j = 2 * i + 1;
- }
- }
-
- if (List[i].Depth > List[j].Depth)
- {
- tmp = List[i];
-
- List[i] = List[j];
-
- List[j] = tmp;
-
- i = j;
- }
- else
- {
- break;
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Check_And_Enqueue
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * If a given ray intersect the object's bounding box then add it
- * to the priority queue.
- *
- * CHANGES
- *
- * Sep 1994 : Pass bounding box seperately.
- * This is needed for the vista/light buffer. [DB]
- *
- * Sep 1994 : Added code to insert infinte objects without testing. [DB]
- *
- ******************************************************************************/
-
- void Check_And_Enqueue(Queue, Node, BBox, rayinfo)
- PRIORITY_QUEUE *Queue;
- BBOX_TREE *Node;
- BBOX *BBox;
- RAYINFO *rayinfo;
- {
- DBL tmin, tmax;
- DBL dmin, dmax;
-
- if (Node->Infinite)
- {
- /* Set intersection depth to -Max_Distance. */
-
- dmin = -Max_Distance;
- }
- else
- {
- Increase_Counter(stats[nChecked]);
-
- if (rayinfo->nonzero[X])
- {
- if (rayinfo->positive[X])
- {
- dmin = (BBox->Lower_Left[X] - rayinfo->slab_num[X]) * rayinfo->slab_den[X];
-
- dmax = dmin + (BBox->Lengths[X] * rayinfo->slab_den[X]);
-
- if (dmax < EPSILON) return;
- }
- else
- {
- dmax = (BBox->Lower_Left[X] - rayinfo->slab_num[X]) * rayinfo->slab_den[X];
-
- if (dmax < EPSILON) return;
-
- dmin = dmax + (BBox->Lengths[X] * rayinfo->slab_den[X]);
- }
-
- if (dmin > dmax) return;
- }
- else
- {
- if ((rayinfo->slab_num[X] < BBox->Lower_Left[X]) ||
- (rayinfo->slab_num[X] > BBox->Lengths[X] + BBox->Lower_Left[X]))
- {
- return;
- }
-
- dmin = -BOUND_HUGE;
- dmax = BOUND_HUGE;
- }
-
- if (rayinfo->nonzero[Y])
- {
- if (rayinfo->positive[Y])
- {
- tmin = (BBox->Lower_Left[Y] - rayinfo->slab_num[Y]) * rayinfo->slab_den[Y];
-
- tmax = tmin + (BBox->Lengths[Y] * rayinfo->slab_den[Y]);
- }
- else
- {
- tmax = (BBox->Lower_Left[Y] - rayinfo->slab_num[Y]) * rayinfo->slab_den[Y];
-
- tmin = tmax + (BBox->Lengths[Y] * rayinfo->slab_den[Y]);
- }
-
- /*
- * Unwrap the logic - do the dmin and dmax checks only when tmin and
- * tmax actually affect anything, also try to escape ASAP. Better
- * yet, fold the logic below into the two branches above so as to
- * compute only what is needed.
- */
-
- /*
- * You might even try tmax < EPSILON first (instead of second) for an
- * early quick out.
- */
-
- if (tmax < dmax)
- {
- if (tmax < EPSILON) return;
-
- /* check bbox only if tmax changes dmax */
-
- if (tmin > dmin)
- {
- if (tmin > tmax) return;
-
- /* do this last in case it's not needed! */
-
- dmin = tmin;
- }
- else
- {
- if (dmin > tmax) return;
- }
-
- /* do this last in case it's not needed! */
-
- dmax = tmax;
- }
- else
- {
- if (tmin > dmin)
- {
- if (tmin > dmax) return;
-
- /* do this last in case it's not needed! */
-
- dmin = tmin;
- }
-
- /* else nothing needs to happen, since dmin and dmax did not change! */
- }
- }
- else
- {
- if ((rayinfo->slab_num[Y] < BBox->Lower_Left[Y]) ||
- (rayinfo->slab_num[Y] > BBox->Lengths[Y] + BBox->Lower_Left[Y]))
- {
- return;
- }
- }
-
- if (rayinfo->nonzero[Z])
- {
- if (rayinfo->positive[Z])
- {
- tmin = (BBox->Lower_Left[Z] - rayinfo->slab_num[Z]) * rayinfo->slab_den[Z];
-
- tmax = tmin + (BBox->Lengths[Z] * rayinfo->slab_den[Z]);
- }
- else
- {
- tmax = (BBox->Lower_Left[Z] - rayinfo->slab_num[Z]) * rayinfo->slab_den[Z];
-
- tmin = tmax + (BBox->Lengths[Z] * rayinfo->slab_den[Z]);
- }
-
- if (tmax < dmax)
- {
- if (tmax < EPSILON) return;
-
- /* check bbox only if tmax changes dmax */
-
- if (tmin > dmin)
- {
- if (tmin > tmax) return;
-
- /* do this last in case it's not needed! */
-
- dmin = tmin;
- }
- else
- {
- if (dmin > tmax) return;
- }
- }
- else
- {
- if (tmin > dmin)
- {
- if (tmin > dmax) return;
-
- /* do this last in case it's not needed! */
-
- dmin = tmin;
- }
-
- /* else nothing needs to happen, since dmin and dmax did not change! */
- }
- }
- else
- {
- if ((rayinfo->slab_num[Z] < BBox->Lower_Left[Z]) ||
- (rayinfo->slab_num[Z] > BBox->Lengths[Z] + BBox->Lower_Left[Z]))
- {
- return;
- }
- }
-
- Increase_Counter(stats[nEnqueued]);
- }
-
- priority_queue_insert(Queue, dmin, Node);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * Create_Rayinfo
- *
- * INPUT
- *
- * Ray - Current ray
- * rayinfo - Rayinfo structure
- *
- * OUTPUT
- *
- * rayinfo
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Dieter Bayer
- *
- * DESCRIPTION
- *
- * Calculate the rayinfo structure for a given ray. It's need for
- * intersection the ray with bounding boxes.
- *
- * CHANGES
- *
- * May 1994 : Creation. (Extracted from Intersect_BBox_Tree)
- *
- ******************************************************************************/
-
- void Create_Rayinfo(Ray, rayinfo)
- RAY *Ray;
- RAYINFO *rayinfo;
- {
- DBL t;
-
- /* Create the direction vectors for this ray */
-
- Assign_Vector(rayinfo->slab_num, Ray->Initial);
-
- if ((rayinfo->nonzero[X] = ((t = Ray->Direction[X]) != 0.0)) != 0)
- {
- rayinfo->slab_den[X] = 1.0 / t;
-
- rayinfo->positive[X] = (Ray->Direction[X] > 0.0);
- }
-
- if ((rayinfo->nonzero[Y] = ((t = Ray->Direction[Y]) != 0.0)) != 0)
- {
- rayinfo->slab_den[Y] = 1.0 / t;
-
- rayinfo->positive[Y] = (Ray->Direction[Y] > 0.0);
- }
-
- if ((rayinfo->nonzero[Z] = ((t = Ray->Direction[Z]) != 0.0)) != 0)
- {
- rayinfo->slab_den[Z] = 1.0 / t;
-
- rayinfo->positive[Z] = (Ray->Direction[Z] > 0.0);
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * create_bbox_node
- *
- * INPUT
- *
- * size - Number of subnodes
- *
- * OUTPUT
- *
- * RETURNS
- *
- * BBOX_TREE * - New node
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static BBOX_TREE *create_bbox_node(size)
- int size;
- {
- BBOX_TREE *New;
-
- New = (BBOX_TREE *)POV_MALLOC(sizeof(BBOX_TREE), "bounding box node");
-
- New->Infinite = FALSE;
-
- New->Entries = size;
-
- Make_BBox(New->BBox, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
-
- if (size)
- {
- New->Node = (BBOX_TREE **)POV_MALLOC(size*sizeof(BBOX_TREE *), "bounding box node");
- }
- else
- {
- New->Node = NULL;
- }
-
- return (New);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * compboxes
- *
- * INPUT
- *
- * in_a, in_b - Elements to compare
- *
- * OUTPUT
- *
- * RETURNS
- *
- * int - result of comparison
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * Sep 1994 : Removed test for infinite objects because it's obsolete. [DB]
- *
- ******************************************************************************/
-
- static int CDECL compboxes(in_a, in_b)
- CONST void *in_a;
- CONST void *in_b;
- {
- BBOX *a, *b;
- BBOX_VAL am, bm;
-
- a = &((*(BBOX_TREE **)in_a)->BBox);
- b = &((*(BBOX_TREE **)in_b)->BBox);
-
- am = 2.0 * a->Lower_Left[Axis] + a->Lengths[Axis];
- bm = 2.0 * b->Lower_Left[Axis] + b->Lengths[Axis];
-
- if (am < bm)
- {
- return (-1);
- }
- else
- {
- if (am == bm)
- {
- return (0);
- }
- else
- {
- return (1);
- }
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * find_axis
- *
- * INPUT
- *
- * Finite - Array of finite elements
- * first, last - Position of elements
- *
- * OUTPUT
- *
- * RETURNS
- *
- * int - Axis to sort along
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Find the axis along which the elements will be sorted.
- *
- * CHANGES
- *
- * Sep 1994 : Initialize local variable which. [DB]
- *
- ******************************************************************************/
-
- static int find_axis(Finite, first, last)
- BBOX_TREE **Finite;
- long first, last;
- {
- int which = X;
- long i;
- DBL e, d = -BOUND_HUGE;
- VECTOR mins, maxs;
- BBOX *bbox;
-
- Make_Vector(mins, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(maxs, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
-
- for (i = first; i < last; i++)
- {
- bbox = &(Finite[i]->BBox);
-
- if (bbox->Lower_Left[X] < mins[X])
- {
- mins[X] = bbox->Lower_Left[X];
- }
-
- if (bbox->Lower_Left[X] + bbox->Lengths[X] > maxs[X])
- {
- maxs[X] = bbox->Lower_Left[X];
- }
-
- if (bbox->Lower_Left[Y] < mins[Y])
- {
- mins[Y] = bbox->Lower_Left[Y];
- }
-
- if (bbox->Lower_Left[Y] + bbox->Lengths[Y] > maxs[Y])
- {
- maxs[Y] = bbox->Lower_Left[Y];
- }
-
- if (bbox->Lower_Left[Z] < mins[Z])
- {
- mins[Z] = bbox->Lower_Left[Z];
- }
-
- if (bbox->Lower_Left[Z] + bbox->Lengths[Z] > maxs[Z])
- {
- maxs[Z] = bbox->Lower_Left[Z];
- }
- }
-
- e = maxs[X] - mins[X];
-
- if (e > d)
- {
- d = e; which = X;
- }
-
- e = maxs[Y] - mins[Y];
-
- if (e > d)
- {
- d = e; which = Y;
- }
-
- e = maxs[Z] - mins[Z];
-
- if (e > d)
- {
- which = Z;
- }
-
- return (which);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * calc_bbox
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Calculate the bounding box containing Finite[first] through Finite[last-1].
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void calc_bbox(BBox, Finite, first, last)
- BBOX *BBox;
- BBOX_TREE **Finite;
- long first, last;
- {
- long i;
- DBL tmin, tmax;
- VECTOR bmin, bmax;
- BBOX *bbox;
-
- COOPERATE_1
-
- Make_Vector(bmin, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(bmax, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
-
- for (i = first; i < last; i++)
- {
- bbox = &(Finite[i]->BBox);
-
- tmin = bbox->Lower_Left[X];
- tmax = tmin + bbox->Lengths[X];
-
- if (tmin < bmin[X]) { bmin[X] = tmin; }
- if (tmax > bmax[X]) { bmax[X] = tmax; }
-
- tmin = bbox->Lower_Left[Y];
- tmax = tmin + bbox->Lengths[Y];
-
- if (tmin < bmin[Y]) { bmin[Y] = tmin; }
- if (tmax > bmax[Y]) { bmax[Y] = tmax; }
-
- tmin = bbox->Lower_Left[Z];
- tmax = tmin + bbox->Lengths[Z];
-
- if (tmin < bmin[Z]) { bmin[Z] = tmin; }
- if (tmax > bmax[Z]) { bmax[Z] = tmax; }
- }
-
- Make_BBox_from_min_max(*BBox, bmin, bmax);
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * build_area_table
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * Generates a table of bound box surface areas.
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static void build_area_table(Finite, a, b, areas)
- BBOX_TREE **Finite;
- long a, b;
- DBL *areas;
- {
- long i, imin, dir;
- DBL tmin, tmax;
- VECTOR bmin, bmax, len;
- BBOX *bbox;
-
- if (a < b)
- {
- imin = a; dir = 1;
- }
- else
- {
- imin = b; dir = -1;
- }
-
- Make_Vector(bmin, BOUND_HUGE, BOUND_HUGE, BOUND_HUGE);
- Make_Vector(bmax, -BOUND_HUGE, -BOUND_HUGE, -BOUND_HUGE);
-
- for (i = a; i != (b + dir); i += dir)
- {
- bbox = &(Finite[i]->BBox);
-
- tmin = bbox->Lower_Left[X];
- tmax = tmin + bbox->Lengths[X];
-
- if (tmin < bmin[X]) { bmin[X] = tmin; }
- if (tmax > bmax[X]) { bmax[X] = tmax; }
-
- tmin = bbox->Lower_Left[Y];
- tmax = tmin + bbox->Lengths[Y];
-
- if (tmin < bmin[Y]) { bmin[Y] = tmin; }
- if (tmax > bmax[Y]) { bmax[Y] = tmax; }
-
- tmin = bbox->Lower_Left[Z];
- tmax = tmin + bbox->Lengths[Z];
-
- if (tmin < bmin[Z]) { bmin[Z] = tmin; }
- if (tmax > bmax[Z]) { bmax[Z] = tmax; }
-
- VSub(len, bmax, bmin);
-
- areas[i - imin] = len[X] * (len[Y] + len[Z]) + len[Y] * len[Z];
- }
- }
-
-
-
- /*****************************************************************************
- *
- * FUNCTION
- *
- * sort_and_split
- *
- * INPUT
- *
- * OUTPUT
- *
- * RETURNS
- *
- * AUTHOR
- *
- * Alexander Enzmann
- *
- * DESCRIPTION
- *
- * -
- *
- * CHANGES
- *
- * -
- *
- ******************************************************************************/
-
- static int sort_and_split(Root, Finite, nFinite, first, last)
- BBOX_TREE **Root;
- BBOX_TREE **Finite;
- long *nFinite, first, last;
- {
- BBOX_TREE *cd;
- long size, i, best_loc;
- DBL *area_left, *area_right;
- DBL best_index, new_index;
-
- Axis = find_axis(Finite, first, last);
-
- size = last - first;
-
- if (size <= 0)
- {
- return (1);
- }
-
- /*
- * Actually, we could do this faster in several ways. We could use a
- * logn algorithm to find the median along the given axis, and then a
- * linear algorithm to partition along the axis. Oh well.
- */
-
- QSORT((void *)(&Finite[first]), (unsigned long)size, sizeof(BBOX_TREE *), compboxes);
-
- /*
- * area_left[] and area_right[] hold the surface areas of the bounding
- * boxes to the left and right of any given point. E.g. area_left[i] holds
- * the surface area of the bounding box containing Finite 0 through i and
- * area_right[i] holds the surface area of the box containing Finite
- * i through size-1.
- */
-
- area_left = (DBL *)POV_MALLOC(size * sizeof(DBL), "bounding boxes");
- area_right = (DBL *)POV_MALLOC(size * sizeof(DBL), "bounding boxes");
-
- /* Precalculate the areas for speed. */
-
- build_area_table(Finite, first, last - 1, area_left);
- build_area_table(Finite, last - 1, first, area_right);
-
- best_index = area_right[0] * (size - 3.0);
-
- best_loc = -1;
-
- /*
- * Find the most effective point to split. The best location will be
- * the one that minimizes the function N1*A1 + N2*A2 where N1 and N2
- * are the number of objects in the two groups and A1 and A2 are the
- * surface areas of the bounding boxes of the two groups.
- */
-
- for (i = 0; i < size - 1; i++)
- {
- new_index = (i + 1) * area_left[i] + (size - 1 - i) * area_right[i + 1];
-
- if (new_index < best_index)
- {
- best_index = new_index;
- best_loc = i + first;
- }
- }
-
- POV_FREE(area_left);
- POV_FREE(area_right);
-
- /*
- * Stop splitting if the BUNCHING_FACTOR is reached or
- * if splitting stops being effective.
- */
-
- if ((size <= BUNCHING_FACTOR) || (best_loc < 0))
- {
- cd = create_bbox_node(size);
-
- for (i = 0; i < size; i++)
- {
- cd->Node[i] = Finite[first+i];
- }
-
- calc_bbox(&(cd->BBox), Finite, first, last);
-
- *Root = (BBOX_TREE *)cd;
-
- if (*nFinite > maxfinitecount)
- {
- /* Prim array overrun, increase array by 50%. */
-
- maxfinitecount = 1.5 * maxfinitecount;
-
- /* For debugging only. */
-
- Debug_Info("Reallocing Finite to %d\n", maxfinitecount);
-
- Finite = (BBOX_TREE **)POV_REALLOC(Finite, maxfinitecount * sizeof(BBOX_TREE *), "bounding boxes");
- }
-
- Finite[*nFinite] = cd;
-
- (*nFinite)++;
-
- return (1);
- }
- else
- {
- sort_and_split(Root, Finite, nFinite, first, best_loc + 1);
-
- sort_and_split(Root, Finite, nFinite, best_loc + 1, last);
-
- return (0);
- }
- }
-
-